package cn.school.iot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.school.common.QueryBaseVo;
import cn.school.common.api.CommonPage;
import cn.school.common.api.CommonResult;
import cn.school.common.rabbitMQ.RabbitSenderService;
import cn.school.common.utils.SysUserUtils;
import cn.school.iot.dao.FaceGateRuleDeviceDao;
import cn.school.iot.dao.FaceGateRuleTimePeriodDao;
import cn.school.iot.dao.StuFaceGateRuleDao;
import cn.school.iot.eneity.CardDto;
import cn.school.iot.eneity.StudentFaceGateRuleDo;
import cn.school.iot.param.StudentRulePageParam;
import cn.school.iot.service.FaceGateRuleTimePeriodService;
import cn.school.iot.vo.FaceGateRuleDevice;
import cn.school.iot.vo.FaceGateRuleTimePeriodReceiveVo;
import cn.school.iot.vo.FaceGateRuleTimePeriodVo;
import cn.school.iot.vo.StudentRuleVo;
import cn.school.sys.entity.SysUser;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 考勤规则Service
 * @ClassName: FaceGateRuleTimePeriodServiceImpl
 * @Author: tzw
 * @Date: 2024/4/1 14:09
 */
@Slf4j
@Service
public class FaceGateRuleTimePeriodServiceImpl extends ServiceImpl<FaceGateRuleTimePeriodDao, FaceGateRuleTimePeriodVo> implements FaceGateRuleTimePeriodService {


    @Resource
    private RabbitSenderService rabbitSenderService;

    @Resource
    private FaceGateRuleDeviceDao faceGateRuleDeviceDao;

    @Resource
    private StuFaceGateRuleDao stuFaceGateRuleDao;

    @Resource
    private FaceGateRuleTimePeriodDao faceGateRuleTimePeriodDao;

    /**
     * 获取规则列表
     * @param vo
     * @param queryVo
     * @return
     */
    @Override
    public IPage<FaceGateRuleTimePeriodVo> getList(FaceGateRuleTimePeriodVo vo, QueryBaseVo queryVo) {
        QueryWrapper<FaceGateRuleTimePeriodVo> queryWrapper = new QueryWrapper<>();

        if (StrUtil.isNotEmpty(queryVo.getBeginTime())) {
            queryWrapper.gt("fgrp.create_time", queryVo.getBeginTime());
        }
        if (StrUtil.isNotEmpty(queryVo.getEndTime())) {
            queryWrapper.lt("fgrp.create_time", queryVo.getEndTime());
        }
        if (StrUtil.isNotEmpty(vo.getDeviceType())){
            queryWrapper.eq("fgrp.device_type", vo.getDeviceType());
        }
        if (StrUtil.isNotEmpty(vo.getTenantId())){
            queryWrapper.eq("fgrp.tenant_id", vo.getTenantId());
        }
        queryWrapper.orderByAsc("fgrp.fgrp_code");

        Page<FaceGateRuleTimePeriodVo> page = new Page<FaceGateRuleTimePeriodVo>(queryVo.getPageNum(),queryVo.getPageSize());
        return this.baseMapper.getList(page, queryWrapper);
    }

    /**
     * 获取规则详情
     * @param id
     * @return
     */
    @Override
    public FaceGateRuleTimePeriodVo getById(Long id) {
        return super.getById(id);
    }

    /**
     * 新增/修改规则
     * @param vo
     * @return
     */
    @Transactional
    @Override
    public int addOrUpdateDeviceRule(FaceGateRuleTimePeriodReceiveVo vo) {
        String tenantId = SysUserUtils.getSysUser().getTenantId();
//        String tenantId = "4";
        FaceGateRuleTimePeriodVo saveVo = new FaceGateRuleTimePeriodVo();
        Map map = new HashMap();
        BeanUtil.copyProperties(vo, saveVo);
        if(saveVo.getId() != null) {
            saveVo.setModifyTime(Calendar.getInstance().getTime());
            saveVo.setModifyBy(SysUserUtils.getSysUser().getId().toString());
            vo.setModifyTime(Calendar.getInstance().getTime());
            vo.setModifyBy(SysUserUtils.getSysUser().getId().toString());
            //操作类型 2：修改
            map.put("type","2");
        } else {
            LambdaQueryWrapper<FaceGateRuleTimePeriodVo> queryAlreadyName = new LambdaQueryWrapper<>();
            queryAlreadyName.eq(FaceGateRuleTimePeriodVo::getFgrpName, saveVo.getFgrpName());
            queryAlreadyName.eq(FaceGateRuleTimePeriodVo::getTenantId, saveVo.getTenantId());
            queryAlreadyName.eq(FaceGateRuleTimePeriodVo::getDeviceType, saveVo.getDeviceType());
            Integer count = super.baseMapper.selectCount(queryAlreadyName);
            if (count >0){
                return -1;
            }
            LambdaQueryWrapper<FaceGateRuleTimePeriodVo> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(FaceGateRuleTimePeriodVo::getFgrpCode).orderByDesc(FaceGateRuleTimePeriodVo::getId).last("limit 1");
            FaceGateRuleTimePeriodVo faceGateRuleTimePeriodVo = super.baseMapper.selectOne(wrapper);
            if (ObjectUtils.isNotNull(faceGateRuleTimePeriodVo)){
                int i = Integer.parseInt(faceGateRuleTimePeriodVo.getFgrpCode()) + 1;
                saveVo.setFgrpCode(String.valueOf(i));
            }else{
                saveVo.setFgrpCode("1");
            }
            saveVo.setCreateTime(Calendar.getInstance().getTime());
            saveVo.setCreateBy(SysUserUtils.getSysUser().getId().toString());
            vo.setCreateTime(Calendar.getInstance().getTime());
            vo.setCreateBy(SysUserUtils.getSysUser().getId().toString());
            vo.setFgrpCode(saveVo.getFgrpCode());
            //操作类型 3：新增
            map.put("type","3");
        }

        saveVo.setFgrpWeekday1(new JSONObject(vo.getFgrpWeekday1()).toString());
        saveVo.setFgrpWeekday2(new JSONObject(vo.getFgrpWeekday2()).toString());
        saveVo.setFgrpWeekday3(new JSONObject(vo.getFgrpWeekday3()).toString());
        saveVo.setFgrpWeekday4(new JSONObject(vo.getFgrpWeekday4()).toString());
        saveVo.setFgrpWeekday5(new JSONObject(vo.getFgrpWeekday5()).toString());
        saveVo.setFgrpWeekday6(new JSONObject(vo.getFgrpWeekday6()).toString());
        saveVo.setFgrpWeekday7(new JSONObject(vo.getFgrpWeekday7()).toString());
        int count = super.saveOrUpdate(saveVo)? 1 : 0;
        if (count > 0) {
            map.put("vo",vo);
            try {
//            rabbitSenderService.sendMqMessage(JSON.toJSONString(map),null);
                rabbitSenderService.sendMqMessage(JSON.toJSONString(map), null,
                        "zhxypt-" + tenantId + "-exchanges-dev",
                        "facegate-" + tenantId + "-routing-dev");
                log.info("FaceGateRuleTimePeriodServiceImpl 新增/修改人脸规则：消息发送到路由Key {} 成功","facegate-" + tenantId + "-routing");
            } catch (Exception e) {
                log.error("FaceGateRuleTimePeriodServiceImpl 新增/修改人脸规则：消息发送到Iot失败->"+e.getMessage());
            }
        }else{
            log.error("FaceGateRuleTimePeriodServiceImpl 新增/修改人脸规则:规则插入/修改失败");
        }
        //发送消息到Iot

        return count;
    }

    /**
     * 删除规则
     * @param id
     * @return
     */
    @Override
    @Transactional
    public int deleteById(Long id) {
        String tenantId = SysUserUtils.getSysUser().getTenantId();
//        String tenantId = "4";
        //查询考勤规则被引用次数条件
        LambdaQueryWrapper<StudentFaceGateRuleDo> getRuleCount = new LambdaQueryWrapper<>();
        getRuleCount.eq(StudentFaceGateRuleDo::getFgrpCode,id);
        getRuleCount.eq(StudentFaceGateRuleDo::getTenantId,tenantId);
        //查询/删除对应考勤规则
        LambdaQueryWrapper<FaceGateRuleTimePeriodVo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FaceGateRuleTimePeriodVo::getFgrpCode,id);
        wrapper.eq(FaceGateRuleTimePeriodVo::getTenantId,tenantId);

        Integer ruleCount = stuFaceGateRuleDao.selectCount(getRuleCount);
        //如果考勤规则未被引用，则删除考勤规则设备表数据
        if (ruleCount != 0){
            return 0;
        }
        LambdaQueryWrapper<FaceGateRuleDevice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FaceGateRuleDevice::getFaceGateRuleId,id);
        queryWrapper.eq(FaceGateRuleDevice::getTenantId,tenantId);
        //删除考勤规则设备对应表数据
        faceGateRuleDeviceDao.delete(queryWrapper);

        FaceGateRuleTimePeriodVo periodVo = super.getOne(wrapper);
        //删除考勤规则
        boolean remove = super.remove(wrapper);
        if(remove){
            //构建发送到Iot消息参数
            Map map = new HashMap();
            FaceGateRuleTimePeriodReceiveVo vo = new FaceGateRuleTimePeriodReceiveVo();
            vo.setFgrpCode(periodVo.getFgrpCode());
            vo.setDeviceType(periodVo.getDeviceType());
            //操作类型 1：删除
            map.put("type","1");
            map.put("vo",vo);
            try {
//            rabbitSenderService.sendMqMessage(JSON.toJSONString(map),null);
                rabbitSenderService.sendMqMessage(JSON.toJSONString(map), null,
                        "zhxypt-" + tenantId + "-exchanges-dev",
                        "facegate-" + tenantId + "-routing-dev");
                log.info("FaceGateRuleTimePeriodServiceImpl 删除人脸规则：消息发送到路由Key {} 成功","facegate-" + tenantId + "-routing");
            } catch (Exception e) {
                log.error("FaceGateRuleTimePeriodServiceImpl 删除人脸规则：消息发送到Iot失败->"+e.getMessage());
            }
            return 1;
        }
        log.error("FaceGateRuleTimePeriodServiceImpl 删除人脸规则：删除失败");
        return 0;
    }

    /**
     * 获取学生信息
     * @param param
     * @return
     */
    @Override
    public CommonResult<CommonPage<StudentRuleVo>> getStudentInfo(StudentRulePageParam param) {
        SysUser sysUser = SysUserUtils.getSysUser();
        boolean isClassTeacher = sysUser.getRoleInfoList().stream().anyMatch(m -> m.getRoleName().equals("班主任"));
        if (isClassTeacher) {
            param.setIsClassTeacher("yes");
            param.setTeacherId(sysUser.getUsername());
        }

        int count = faceGateRuleTimePeriodDao.queryCount(param);
        List<StudentRuleVo> studentInfoList = faceGateRuleTimePeriodDao.queryLimit(param);
        IPage<StudentRuleVo> studentInfoPage = new Page<>();
        studentInfoPage.setTotal(count);
        studentInfoPage.setSize(param.getPageSize());
        studentInfoPage.setCurrent(param.getPageNum());
        studentInfoPage.setRecords(studentInfoList);
        return CommonResult.success(CommonPage.restPage(studentInfoPage));
    }

    /**
     * 同步规则
     * @param type
     * @return
     */
    @Override
    public CommonResult<CommonPage> syncFaceGateRule(String type) {
        String  tenantId = SysUserUtils.getSysUser().getTenantId();
//        String  tenantId = "4";
        log.info("同步人脸规则：同步开始");
        Map map = new HashMap();
        FaceGateRuleTimePeriodReceiveVo vo = new FaceGateRuleTimePeriodReceiveVo();
        vo.setDeviceType(type);
        map.put("vo",vo);
        //操作类型：5 同步规则
        map.put("type","5");
        try {
//            rabbitSenderService.sendMqMessage(JSON.toJSONString(map),null);
            rabbitSenderService.sendMqMessage(JSON.toJSONString(map), null,
                    "zhxypt-" + tenantId + "-exchanges-dev",
                    "facegate-" + tenantId + "-routing-dev");
            log.info("FaceGateRuleTimePeriodServiceImpl 同步人脸规则：消息发送到路由Key {} 成功","facegate-" + tenantId + "-routing");
        } catch (Exception e) {
            log.error("FaceGateRuleTimePeriodServiceImpl 同步人脸规则：消息发送到Iot失败->"+e.getMessage());
            return CommonResult.failed();
        }
        return CommonResult.success();
    }

    /**
     * 接受门禁规则
     * @param records
     * @return
     */
    @Override
    public CommonResult<CommonPage> receiveGateRule(String records) {
        log.info("FaceGateRuleTimePeriodServiceImpl 同步人脸规则：开始解析规则");
        Map map = JSON.parseObject(records, Map.class);
        try {
            if(map != null && map.size() > 0){
                List<FaceGateRuleTimePeriodVo> faceGateRuleTimePeriodVos = JSON.parseArray(JSON.toJSONString(new ArrayList<>(map.keySet()).get(0)), FaceGateRuleTimePeriodVo.class);
                List<FaceGateRuleDevice> faceGateRuleDevices = JSON.parseArray(JSON.toJSONString(new ArrayList<>(map.values()).get(0)), FaceGateRuleDevice.class);
                faceGateRuleTimePeriodDao.insertBatch(faceGateRuleTimePeriodVos);
                faceGateRuleDeviceDao.insertBatch(faceGateRuleDevices);
            }else{
                log.info("同步人脸规则：接收到Iot请求，消息内容为空");
                return CommonResult.success();
            }
        } catch (Exception e) {
            log.error("FaceGateRuleTimePeriodServiceImpl 同步人脸规则：接收到Iot请求，解析规则出现异常 Exception：{}",e.getMessage());
            return CommonResult.failed();
        }
        log.info("FaceGateRuleTimePeriodServiceImpl 同步人脸规则：人脸规则同步成功");
        return CommonResult.success();
    }

    /**
     * 接收学生对应规则
     * @param records
     * @return
     */
    @Override
    public CommonResult<CommonPage> receiveStudentRuleRecords(String records) {
        //接收到的所有学生对应规则信息
        List<StudentFaceGateRuleDo> insterList = new ArrayList<>();
        log.info("FaceGateRuleTimePeriodServiceImpl 同步学生绑定规则：开始解析规则");
        Map map = JSON.parseObject(records, Map.class);
        if (map == null){
            log.error("FaceGateRuleTimePeriodServiceImpl 同步学生绑定规则：接收到Iot请求，内容为空");
            return CommonResult.success();
        }
        String devType = (String) map.get("devType");
        String tenantId = (String) map.get("tenantId");
        List<CardDto> cardList = JSON.parseArray(JSON.toJSONString(new ArrayList<>(map.values()).get(1)), CardDto.class);
        List<Long> devIds = JSON.parseArray(JSON.toJSONString(new ArrayList<>(map.values()).get(3)), Long.class);
        log.info("FaceGateRuleTimePeriodServiceImpl 同步学生绑定规则：接收到Iot请求，租户Id：{}，设备类型：{},学生数量：{}",tenantId,devType,cardList.size());
        LambdaQueryWrapper<FaceGateRuleDevice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FaceGateRuleDevice::getTenantId,tenantId);
        List<FaceGateRuleDevice> faceGateRuleDevices = faceGateRuleDeviceDao.selectList(queryWrapper);
        for (Long devId : devIds) {
            for (CardDto cardDto : cardList) {
                List<FaceGateRuleDevice> faceGateRuleDeviceList = faceGateRuleDevices.stream()
                        .filter(faceGateRuleDevice ->
                                Objects.equals(faceGateRuleDevice.getDeviceId(), devId)
                                        && faceGateRuleDevice.getDeviceRuleIndex().equals(String.valueOf(cardDto.getRulerNo())))
                        .collect(Collectors.toList());
                if (!faceGateRuleDeviceList.isEmpty()){
                    StudentFaceGateRuleDo faceGateRuleDo = new StudentFaceGateRuleDo();
                    if (StringUtils.isNotBlank(cardDto.getCardNo())){
                        faceGateRuleDo.setStudentId(cardDto.getCardNo());
                    } else if (StringUtils.isNotBlank(cardDto.getUserId())) {
                        faceGateRuleDo.setStudentId(cardDto.getUserId());
                    }
                    faceGateRuleDo.setFgrpCode(String.valueOf(faceGateRuleDeviceList.get(0).getFaceGateRuleId()));
                    faceGateRuleDo.setDeviceType(String.valueOf(devId));
                    faceGateRuleDo.setTenantId(tenantId);
                    faceGateRuleDo.setCreateTime(new Date());
                    faceGateRuleDo.setCreateBy(tenantId);
                    faceGateRuleDo.setDeviceType(devType);
                    insterList.add(faceGateRuleDo);
                }
            }
        }
        LambdaQueryWrapper<StudentFaceGateRuleDo> doLambdaQueryWrapper = new LambdaQueryWrapper<>();
        doLambdaQueryWrapper.eq(StudentFaceGateRuleDo::getTenantId,tenantId);
        stuFaceGateRuleDao.delete(doLambdaQueryWrapper);
        List<List<StudentFaceGateRuleDo>> partition = ListUtils.partition(insterList, 100);
        for (List<StudentFaceGateRuleDo> studentFaceGateRuleDos : partition) {
            stuFaceGateRuleDao.insertBatch(studentFaceGateRuleDos);
        }
        log.info("FaceGateRuleTimePeriodServiceImpl 同步学生绑定规则：学生对应规则同步成功,共有{}条数据",insterList.size());
        return CommonResult.success();
    }

}
